package com.gin.no_gay_alliance.manager;

import android.util.Log;

import androidx.annotation.NonNull;

import com.gin.common.utils.TimeAgo;
import com.gin.jackson.utils.ObjectUtils;
import com.gin.nga.callback.JsonCallback;
import com.gin.nga.client.NgaClient;
import com.gin.nga.exception.NgaException;
import com.gin.nga.method.NukeApi;
import com.gin.nga.response.body.UserOldNameBody;
import com.gin.nga.response.body.nuke.UserInfoBody;
import com.gin.nga.response.field.user.UserInfoNuke;
import com.gin.no_gay_alliance.app.MyApplication;
import com.gin.no_gay_alliance.callback.Bundle;
import com.gin.no_gay_alliance.callback.Callback;
import com.gin.no_gay_alliance.database.dao.IpLocationHistoryDao;
import com.gin.no_gay_alliance.database.dao.NgaUserInfoDao;
import com.gin.no_gay_alliance.database.entity.IpLocationHistory;
import com.gin.no_gay_alliance.database.entity.NgaUserInfo;

import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Locale;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;

/**
 * 用户信息管理器
 *
 * @author : ginstone
 * @version : v1.0.0
 * @since : 2023/8/10 15:01
 **/
public class UserInfoManager {
    public static final String TAG = UserInfoManager.class.getSimpleName();
    /**
     * 缓存对象
     */
    private final HashMap<String, Bundle<UserInfoNuke>> cache = new HashMap<>();

    public UserInfoManager() {
        Log.d(TAG, "创建:用户信息管理器");
    }

    /**
     * 获取IP属地，如果距离上次请求间隔小于一定间隔则直接使用缓存数据
     *
     * @param userId   用户id
     * @param callback 回调
     */
    public void getIpLocation(long userId, Callback<String> callback) {
        NgaUserInfoDao ngaUserInfoDao = MyApplication.app.ngaDatabase.ngaUserInfoDao();
        NgaUserInfo ngaUserInfo = ngaUserInfoDao.get(userId);
        long now = System.currentTimeMillis() / 1000;
        // 间隔
        long duration = now - ngaUserInfo.ipLocationTimestamp;
        if (duration <= TimeUnit.HOURS.toSeconds(6)) {
            callback.onSuccess(ngaUserInfo.ipLocation);
        } else {
            callback.beforeRequest();
            request(true, userId, null, data -> callback.onSuccess(data.getIpLocation()));
        }
    }

    public void getOldName(long userId, Callback<Collection<UserOldNameBody.OldName>> callback) {
        // 客户端
        NgaClient client = MyApplication.getClient();

        callback.beforeRequest();

        NukeApi.userOldNameGet(client, userId).async(new JsonCallback<UserOldNameBody>() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                callback.onFailure(call, e);
            }

            @Override
            public void onSuccess(UserOldNameBody body) {
                callback.onSuccess(body.getData().values());
            }

            @Override
            public void handleException(NgaException e) {
                callback.handleException(e);
            }
        });
    }


    /**
     * 从数据中查询账号状态
     *
     * @param userId 用户id
     */
    public String getAccountStatusFromDatabase(long userId) {
        NgaUserInfoDao ngaUserInfoDao = MyApplication.app.ngaDatabase.ngaUserInfoDao();
        NgaUserInfo ngaUserInfo = ngaUserInfoDao.get(userId);
        if (ngaUserInfo != null && ngaUserInfo.accountStatus != null) {
            String label = ngaUserInfo.accountStatus.label;
            String ago = TimeAgo.ago(ngaUserInfo.accountStatusTimestamp);
            return String.format(Locale.CHINA, "%s (%s)", label, ago);
        } else {
            Log.d(this.getClass().getSimpleName(), "未找到用户账号状态");
        }
        return null;
    }

    /**
     * 执行请求
     *
     * @param ignoreCache 是否忽略缓存
     * @param userId      用户id
     * @param username    用户名
     * @param callback    回调
     */
    public void request(boolean ignoreCache, Long userId, String username, @NonNull Callback<UserInfoNuke> callback) {
        // 客户端
        NgaClient client = MyApplication.getClient();
        // 回调
        JsonCallback<UserInfoBody> cb = new JsonCallback<UserInfoBody>() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                callback.onFailure(call, e);
            }

            /**
             * 执行成功回调
             * @param body body字符串
             */
            @Override
            public void onSuccess(UserInfoBody body) {
                UserInfoNuke data = body.getData();
                Bundle<UserInfoNuke> bundle = new Bundle<>(data, 30, TimeUnit.MINUTES);
                cache.put(getIdKey(data.getUserId()), bundle);
                cache.put(getNameKey(data.getUsername()), bundle);

                // 缓存IP属地
                NgaUserInfoDao ngaUserInfoDao = MyApplication.app.ngaDatabase.ngaUserInfoDao();
                IpLocationHistoryDao ipLocationHistoryDao = MyApplication.app.ngaDatabase.ipLocationHistoryDao();
                NgaUserInfo ngaUserInfo = ngaUserInfoDao.get(data.getUserId());
                if (ngaUserInfo == null) {
                    // 没有缓存，新建
                    ngaUserInfo = new NgaUserInfo(data);
                    ngaUserInfoDao.add(ngaUserInfo);
                    Log.d(TAG, "创建新用户信息缓存: " + ngaUserInfo);
                } else {
                    // 缓存已存在，更新IP属地
                    Log.d(TAG, "已存在用户信息缓存: " + ngaUserInfo);
                    Log.d(TAG, "更新IP属地: " + data.getUsername() + " " + data.getIpLocation());
                    long now = System.currentTimeMillis() / 1000;
                    ngaUserInfoDao.updateIpLocation(data.getUserId(), data.getIpLocation(), now);
                    // 添加IP属地历史
                    ipLocationHistoryDao.add(new IpLocationHistory(data.getUserId(), data.getIpLocation()));
                    if (data.getAccountStatus() != null) {
                        Log.d(TAG, "更新账号状态: " + data.getUsername() + " " + data.getAccountStatus().label);
                        ngaUserInfoDao.updateStatus(data.getUserId(), data.getAccountStatus(), now);
                    }
                }

                callback.onSuccess(data);
            }

            @Override
            public void handleException(NgaException e) {
                callback.handleException(e);
            }
        };

        if (userId != null && userId > 0) {
            String key = getIdKey(userId);
            // 检查缓存
            if (Bundle.checkCache(ignoreCache, cache, key, callback)) {
                return;
            }
            callback.beforeRequest();
            // 执行请求
            NukeApi.userInfoGet(client, userId).async(cb);
        } else if (!ObjectUtils.isEmpty(username)) {
            String key = getNameKey(username);
            // 检查缓存
            if (Bundle.checkCache(ignoreCache, cache, key, callback)) {
                return;
            }
            callback.beforeRequest();
            // 执行请求
            NukeApi.userInfoGet(client, username).async(cb);
        }
    }

    @NonNull
    private static String getNameKey(String username) {
        return "name_" + username;
    }

    @NonNull
    private static String getIdKey(long userid) {
        return "id_" + userid;
    }
}
